package org.wattdepot.cli.processor;

import org.wattdepot.cli.command.ChartPower;
import org.wattdepot.cli.command.FuelTypes;
import org.wattdepot.cli.command.HelpMenu;
import org.wattdepot.cli.command.ListSources;
import org.wattdepot.cli.command.ListSummary;
import org.wattdepot.cli.command.PowerGeneratedTime;
import org.wattdepot.cli.command.PowerStatistic;
import org.wattdepot.cli.command.SensorDataDay;
import org.wattdepot.cli.command.SensorDataTime;
import org.wattdepot.cli.command.TotalGenerated;
import org.wattdepot.cli.command.CarbonContent;
import org.wattdepot.cli.command.TotalPowerFuelType;
import org.wattdepot.cli.command.WattDepotCliCommand;
import org.wattdepot.client.WattDepotClient;
import java.util.List;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

/**
 * A simple command line interface to WattDepot that shows basic connection and processing. View the
 * README.txt file for sample commands.
 * 
 * @author Remy Baumgarten
 * @author Kevin Chiogioji
 */
public class CommandLineInterface {

  /** The URL to the public WattDepot Server. */
  private String hostUri = "http://server.wattdepot.org:8182/wattdepot/";
  /** Holds an instance of the WattDepot client. */
  protected WattDepotClient client;
  /** Carriage return on this operating system. */
  protected String cr = System.getProperty("line.separator");
  /** Resource not available error message. */
  protected static final String error404 = "This resource is not available";
  /** Error message. */
  protected static final String errorTimeStamp = "Invalid TimeStamp Formatting";
  /** Error message. */
  protected static final String error401 = "Not Authorized to view this resource";
  /** Error message. */
  protected static final String errorXML =
      "Bad XML from server, check to see your command is within range";
  /** Error message. */
  protected static final String errorClient = "Client Problem";
  /** Error message. */
  protected static final String errorFile = "File system error";
  /** Debug Switch. */
  protected static final Boolean DEBUG = false;
  /** Bad command string. */
  protected static final String commandError = "bad command";
  /** Sampling interval string. */
  protected static final String interval = "sampling-interval";

  /**
   * Connect to the service and execute some simple commands. Returns immediately if a connection to
   * the service could not be obtained.
   */
  public CommandLineInterface() {
    client = new WattDepotClient(this.hostUri);
    // Fail if cannot connect
    if (!client.isHealthy()) {
      System.out.println("Failed to connect to " + client.getWattDepotUri());
      return;
    }
  }

  /**
   * Menu.
   * 
   */
  public void menu() {
    String input = null;
    String command = null;
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    Map<String, WattDepotCliCommand> commandMap = new HashMap<String, WattDepotCliCommand>();
    commandMap.put("sources", new ListSources());
    commandMap.put("summary", new ListSummary());
    commandMap.put("sensordata", new SensorDataTime());
    commandMap.put("dailysensordata", new SensorDataDay());
    commandMap.put("power", new PowerGeneratedTime());
    commandMap.put("powerstats", new PowerStatistic());
    commandMap.put("chart", new ChartPower());
    commandMap.put("total", new TotalGenerated());
    commandMap.put("fueltypes", new FuelTypes());
    commandMap.put("help", new HelpMenu());
    commandMap.put("carboncontent", new CarbonContent());
    commandMap.put("totalpower", new TotalPowerFuelType());
    if (client.isHealthy()) {
      System.out.println("Connected to " + this.hostUri);
    }
    System.out.print(cr + ">> ");
    try {
      while ((input = br.readLine()) != null) {
        List<String> cList = deliminateCommand(input);
        command = cList.remove(0);
        WattDepotCliCommand commandInstance = commandMap.get(command);
        if (input.equalsIgnoreCase("quit")) {
          return;
        }
        else if (commandInstance == null) {
          System.out.println("Bad Command.");
        }
        else {
          System.out.print(commandInstance.doCommand(cList));
        }
        System.out.print(cr + ">> ");
      }
    }
    catch (IOException ioe) {
      System.out.println(errorFile);
    }
  }

  /**
   * Tokenizes the command(s) entered and puts them into an ArrayList.
   * 
   * @param command String of commands entered by user.
   * @return ArrayList<String> delimited list of commands
   */
  public List<String> deliminateCommand(String command) {
    StringTokenizer st = new StringTokenizer(command);
    List<String> commands = new ArrayList<String>();
    try {
      // Tokenize string and add to ArrayList
      while (st.hasMoreTokens()) {
        commands.add(st.nextToken());
      }

      // For each command, check that all keywords for the command are correct
      // If command is valid, remove keywords such as source, day, etc. so list only contains
      // command and parameters

      if (commands.get(0).equalsIgnoreCase("sensordata")) {
        if (commands.get(2).equalsIgnoreCase("timestamp")) {
          commands.remove(2);
        }
        else {
          commands.add(0, commandError);
        }
      }
      else if (commands.get(0).equalsIgnoreCase("dailysensordata")) {
        if (commands.get(2).equalsIgnoreCase("day")) {
          commands.remove(2);
        }
        else {
          commands.add(0, commandError);
        }
      }
      else if (commands.get(0).equalsIgnoreCase("power")) {
        if (commands.get(3).equalsIgnoreCase("timestamp")) {
          commands.remove(3);
        }
        else {
          commands.add(0, commandError);
        }
      }
      else if (commands.get(0).equalsIgnoreCase("powerstats")) {
        if (commands.get(3).equalsIgnoreCase("day") && commands.get(5).equalsIgnoreCase(interval)
            && commands.get(7).equalsIgnoreCase("statistic")) {
          commands.remove(3);
          commands.remove(4);
          commands.remove(5);
        }
        else {
          commands.add(0, commandError);
        }
      }
      else if (commands.get(0).equalsIgnoreCase("total")) {
        if (commands.get(2).equalsIgnoreCase("generated")
            && commands.get(4).equalsIgnoreCase("day")
            && commands.get(6).equalsIgnoreCase(interval)) {
          commands.remove(2);
          commands.remove(3);
          commands.remove(4);
        }
        else {
          commands.add(0, commandError);
        }
      }
      // Check if command begins with "chart" and edit list so only the command and parameters
      // remain
      else if (commands.get(0).equalsIgnoreCase("chart")) {
        if (commands.get(1).equalsIgnoreCase("power") && commands.get(6).equalsIgnoreCase(interval)
            && commands.get(8).equalsIgnoreCase("file")) {
          commands.remove(1);
          commands.remove(5);
          commands.remove(6);
        }
        else {
          commands.add(0, commandError);
        }
      }
      else if (commands.get(0).equalsIgnoreCase("totalpower")) {
        if (commands.get(3).equalsIgnoreCase("fuelType")) {
          commands.remove(3);
        }
        else {
          commands.add(0, commandError);
        }
      }
      else if (commands.get(0).equalsIgnoreCase("carboncontent")) {
        if (commands.get(3).equalsIgnoreCase(interval)) {
          commands.remove(3);
        }
        else {
          commands.add(0, commandError);
        }
      }
    }
    catch (IndexOutOfBoundsException iobe) {
      commands.add("Bad command.");
      return commands;
    }
    return commands;
  }

  /**
   * The main program that is invoked from 'java -jar wattdepot-cli.jar'.
   * 
   * @param args All args are ignored.
   * @throws Exception - fix me
   */
  public static void main(String[] args) throws Exception {
    System.out.println("Starting CLI.");
    CommandLineInterface cli = new CommandLineInterface();
    cli.menu();
    System.out.println("Exiting CLI.");
  }

}
